﻿using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input;
using Rhino.Input.Custom;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using YangTools.RhinoHelper;

namespace YangTools.Realization
{
    class BlockSubObjects
    {
        /// <summary>
        /// 将图块的子物件的颜色改成给定的来源
        /// </summary>
        internal void ColorAs(ObjectColorSource cs)
        {
            // 1、选择需要操作的图块
            var blockObjects = RhinoHelper.Selection.GetObjects("请选择需要设置为唯一的图块：", ObjectType.InstanceReference, 1, 0);

            // 统计图块定义的索引
            List<int> instanceDefinitionIndex = GetBlockIndex(blockObjects);

            // 改变属性
            Func<ObjectAttributes, ObjectAttributes> f = (a) =>
            {
                a.ColorSource = cs;
                return a;
            };
            Block.ChangeSubObjectsAttribute(instanceDefinitionIndex, f);
        }

        /// <summary>
        /// 像图块中添加物体
        /// </summary>
        /// <param name="keepAddObjects">保留添加的物体在rhino中</param>
        internal void AddToBlock(bool keepAddObjects)
        {
            // 1、选中要添加的物体
            // 2、选择要加入的图块
            // 3、获取图块的原本的物体
            // 4、将物体通过图块的基准点和原点的向量移动到原点
            // 5、重设图块的物体
            var objectsToAdd = Selection.GetObjects("选择需要添加的物体：");
            var blockToAdd = Selection.GetBlocks("选择要添加到的图块：", 1, -1);

            if (blockToAdd.Count==0) return;
            var block = blockToAdd[0];

            var blockDefinition = block.InstanceDefinition;
            var blockObjects = blockDefinition.GetObjects().Select(i => i.Geometry).ToList();
            var basePoint = block.InsertionPoint;

            var move = new Point3d(0, 0, 0) - basePoint;
            var xform = Transform.Translation(move);

            foreach (var item in objectsToAdd)
            {
                var guid = RhinoDoc.ActiveDoc.Objects.Transform(item, xform, !keepAddObjects);
                var o = RhinoDoc.ActiveDoc.Objects.Find(guid);
                blockObjects.Add(o.Geometry);
                RhinoDoc.ActiveDoc.Objects.Delete(o);
            }

            RhinoDoc.ActiveDoc.InstanceDefinitions.ModifyGeometry(blockDefinition.Index, blockObjects);
        }

        /// <summary>
        /// 从图块中移除物体
        /// </summary>
        /// <param name="keepRemovedObjects">是否保留删除的物体到rhino中</param>
        internal void RemoveFromBlock(bool keepRemovedObjects)
        {
            // 1、选择要操作的图块
            var blockToAdd = Selection.GetBlocks("选择要操作的图块：", 1, -1);
            var block = blockToAdd[0];

            // 2、隐藏图块，锁定其他所有物体，并显示图块的子物体
            block.Attributes.Visible = false;
            block.CommitChanges();

                // 锁定所有物体，此时还没有添加图块里的物体，所以只锁定了其他所有物体
            foreach (var id in RhinoDoc.ActiveDoc.Objects) RhinoDoc.ActiveDoc.Objects.Lock(id, true);
            RhinoDoc.ActiveDoc.Views.Redraw();

                // 显示图块子物体
            var objs = block.GetSubObjects(); // 这直接得到的就是变形后的物体
            List<Guid> gs = new List<Guid>(objs.Length);
            foreach (var item in objs)
            {
                Guid g = RhinoDoc.ActiveDoc.Objects.Add(item.Geometry);
                gs.Add(g);
            }
            RhinoDoc.ActiveDoc.Views.Redraw();

            // 3、选择要删除的物体（选择物体时保证只能选择图块中的物体），并找到物体在图块子物体中的索引
            var removeObjects = Selection.GetObjects("选择从图块中移除的物体：", ObjectType.AnyObject, 1, objs.Length, true, false, (RhinoObject rhObject, GeometryBase geometry, ComponentIndex componentIndex) =>gs.Contains(rhObject.Id))
                                .Select(i=>i.Id);
            List<int> removeIndex = new List<int>();

            for (int i = 0; i < gs.Count; i++)
            {
                if (removeObjects.Contains(gs[i])) removeIndex.Add(i);
            }

            // 4、从定义中删除相应索引的物体
            var definitionObjects = block.InstanceDefinition.GetObjects().Select(o => o.Geometry).ToList();
            foreach (var index in removeIndex)
            {
                definitionObjects.RemoveAt(index);
            }
            
            RhinoDoc.ActiveDoc.InstanceDefinitions.ModifyGeometry(block.InstanceDefinition.Index, definitionObjects);

            // 5、删除 第2步 中添加的图块的子物体， 显示 第2步 隐藏的图块
            block.Attributes.Visible = true;
            block.CommitChanges();
            if (keepRemovedObjects)
            {
                foreach (var index in removeIndex)
                {
                    gs.RemoveAt(index);
                }
            }
            RhinoDoc.ActiveDoc.Objects.Delete(gs, true);

            foreach (var id in RhinoDoc.ActiveDoc.Objects) RhinoDoc.ActiveDoc.Objects.Unlock(id, true); // 解锁所有物体
            RhinoDoc.ActiveDoc.Views.Redraw(); // 重绘视窗
        }


        /// <summary>
        /// 获取图块的定义的索引
        /// </summary>
        /// <param name="blockObjects">要搜索的图块引例</param>
        /// <returns>返回不重复的图块定义索引</returns>
        private static List<int> GetBlockIndex(List<RhinoObject> blockObjects)
        {
            List<int> instanceDefinitionIndex = new List<int>();
            foreach (var item in blockObjects)
            {
                var block = item as InstanceObject;
                int index = block.InstanceDefinition.Index;
                if (!instanceDefinitionIndex.Contains(index)) instanceDefinitionIndex.Add(index);
            }

            return instanceDefinitionIndex;
        }

    }
}
